package com.example.bookmall.service.impl;

import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.bookmall.entity.IdentifierType;
import com.example.bookmall.entity.Result;
import com.example.bookmall.entity.usercore.*;
import com.example.bookmall.mapper.UserMapper;
import com.example.bookmall.service.UserService;
import com.example.bookmall.utils.JwtUtil;
import com.example.bookmall.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.Instant;
import java.time.LocalDateTime;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


@Service
public class UserServiceImpl  implements UserService {

    // 用于生成唯一ID的计数器（处理同一毫秒内的并发请求）
    private static final AtomicInteger COUNTER = new AtomicInteger(0);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //通过邮箱查询用户
    @Override
    public User selectByEmail(String email) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
    }

    //通过手机号查询用户
    @Override
    public User selectByPhone(String phone) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
    }

    //通过用户名查询用户
    @Override
    public User findByUserName(String username) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    //获取普通用户所有
    @Override
    public List<User> listCommonUser() {
        List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("role", 1));
//        过滤掉字段deleted为1的记录
        return userList.stream().filter(user -> user.getDeleted() == 0).toList();
    }

    //获取所有用户 包括管理员
    @Override
    public List<User> listAllUser() {
        List<User> userList = userMapper.selectList(new QueryWrapper<User>());
        return userList.stream().filter(user -> user.getDeleted() == 0).toList();
    }

    //通过id查询用户
    @Override
    public User findById(Integer userId) {
        return userMapper.selectById(userId);
    }

    //修改用户个人密码
    @Override
    public Result<Object> updatePwd(PwdString pwdString,String token) {
        //把原密码 转换 成加密模式 比对数据库的密码
        String oldpwd=pwdString.getOldpwd();

        String newpwd=pwdString.getNewpwd();
        String Isnewpwd=pwdString.getIsnewpwd();

        Map<String,Object> map= ThreadLocalUtil.get();
        //获取的是拦截器里面ThreadLocal得到的map类型
        Integer userId = (Integer) map.get("userId");
        User loginuser = userMapper.selectById(userId);

        if(oldpwd==null||newpwd==null||Isnewpwd==null){
            return Result.error("请输入完整信息");
        }

        if(!loginuser.getPassword().equals(MD5.create().digestHex(oldpwd))){
            return Result.error("原密码出错");
        }
        //新密码 和确认密码 比较
        if(!newpwd.equals(Isnewpwd)){
            return Result.error("俩次密码不一致");
        }

        // 密码复杂度检查
        if (!isValidPassword(newpwd)) {
            return Result.error("新密码强度不足，至少包含8位字符，包含大小写字母、数字和特殊字符");
        }

        //加密新密码
        String updatepwd=MD5.create().digestHex(newpwd);

        // 更新数据库中的密码
        loginuser.setPassword(updatepwd);
        userMapper.updateById(loginuser);

        //当密码更新成功后，删除之前的token
        //需要根据键来删，因为之前用的是token也作为键，所以要知道原来的token是多少
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        //根据键来删除token
        operations.getOperations().delete(token);
        return Result.success("密码更新成功");
    }

    //修改用户信息
    @Override
    public Result updateUserProfile(UpdateData updateData) {
        // 更新用户信息
        Map<String,Object> map= ThreadLocalUtil.get();
        //获取的是拦截器里面ThreadLocal得到的map类型
        Integer userId = (Integer) map.get("userId");
        User loginuser = userMapper.selectById(userId);

        // 获取需要更新的字段
        String username = updateData.getUsername();
        String phone = updateData.getPhone();
        String email = updateData.getEmail();
        Integer gender = updateData.getGender();

        if (!StringUtils.hasText(username)) {
            return Result.error("用户名不能为空");
        }

        // 邮箱正则
        String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
        // 手机号正则 (示例为中国大陆手机号)
        String phoneRegex = "^1[3-9]\\d{9}$";

        if(StringUtils.hasText(loginuser.getEmail())){
            // 如果原来用户的邮箱不为空，修改时邮箱不能为空
            if (!StringUtils.hasText(loginuser.getEmail())) {
                return Result.error("邮箱不能为空");
            }
            if (!email.equals(loginuser.getEmail())) {
                System.out.println("loginuser的邮箱"+email);

                if(!email.matches(emailRegex)){
                    return Result.error("邮箱格式错误");
                }

                User user = isIdentifierRegistered(email, IdentifierType.EMAIL);
                if (user != null) {
                    return Result.error("邮箱已被注册用户使用");
                }

                loginuser.setEmail(email);
            }
        }

        //为null返回false
        if(!StringUtils.hasText(loginuser.getEmail())){
            // 如果原来用户的邮箱为空，修改时邮箱可以为空或更新
            if (StringUtils.hasText(email)) {
                //邮箱输入不为空

                // 检查邮箱格式
                if(!email.matches(emailRegex)){
                    return Result.error("邮箱格式错误");
                }
                // 检查邮箱是否存在
                User user = isIdentifierRegistered(email, IdentifierType.EMAIL);
                if (user != null) {
                    return Result.error("邮箱已存在");
                }

                loginuser.setEmail(email);
            }
        }

        if(StringUtils.hasText(loginuser.getPhone())){
            // 如果原来用户的电话不为空，修改时电话不能为空
            if (!StringUtils.hasText(phone)) {
                return Result.error("电话号码不能为空");
            }
            if (!phone.equals(loginuser.getPhone())) {

                if(!phone.matches(phoneRegex)){
                    return Result.error("电话格式错误");
                }

                User user = isIdentifierRegistered(phone, IdentifierType.PHONE);
                if (user != null) {
                    return Result.error("电话号码已被注册用户使用");
                }

                loginuser.setPhone(phone);
            }
        }

        if(!StringUtils.hasText(loginuser.getPhone())){
            // 如果原来用户的电话为空，修改时电话可以为空或更新
            if (StringUtils.hasText(phone)) {

                if(!phone.matches(phoneRegex)){
                    return Result.error("电话格式错误");
                }

                User user = isIdentifierRegistered(phone, IdentifierType.PHONE);
                if (user != null) {
                    return Result.error("电话号码已被注册用户使用");
                }

                loginuser.setPhone(phone);
            }
        }

        loginuser.setUsername(username);
        loginuser.setGender(gender);

        return userMapper.updateById(loginuser) > 0 ? Result.success() : Result.error("更新用户信息失败");
    }

    //修改头像
    @Override
    public Result updateAvatar(String avatar, Integer userId) {

        User user =userMapper.selectById(userId);

        user.setAvatar(avatar);

        int result = userMapper.updateById(user);
        return result>0?Result.success():Result.error("更新用户头像失败");
    }

    //注册
    @Override
    public Result register(RegisterDTO registerDTO) {
        //TODO:注册的时候要设置默认头像
        // 验证输入
        if (!StringUtils.hasText(registerDTO.getIdentifier()) ||
                !StringUtils.hasText(registerDTO.getPassword())) {
           return Result.error("邮箱/手机号和密码不能为空");
        }

        // 识别标识类型 检查是邮箱还是手机号
        IdentifierType type = identifyIdentifierType(registerDTO.getIdentifier());
        if (type == null) {
            return Result.error("无效的邮箱或手机号格式");
        }

        // 检查是否已注册
        if (isIdentifierRegistered(registerDTO.getIdentifier(), type)!=null) {
            return Result.error("该用户已注册");
        }

        //  检查密码
        if(StringUtils.isEmpty(registerDTO.getRepassword())&&StringUtils.isEmpty(registerDTO.getPassword())){
            return Result.error("密码不能为空");
        }
        if(!registerDTO.getRepassword().equals(registerDTO.getPassword())){
            return Result.error("两次密码不一致");
        }

        // 密码复杂度检查
        if (!isValidPassword(registerDTO.getPassword())) {
            return Result.error("密码强度不足，至少包含8位字符，包含大小写字母、数字和特殊字符");
        }

        // 创建用户
        User user = new User();
        if (type == IdentifierType.EMAIL) {
            user.setEmail(registerDTO.getIdentifier());
        } else {
            user.setPhone(registerDTO.getIdentifier());
        }
        String mPassword = MD5.create().digestHex(registerDTO.getPassword());
        user.setPassword(mPassword);
        user.setCreateTime(LocalDateTime.now());
        // 设置用户角色
        user.setRole(1);
        // 生成随机用户名（时间戳+计数器）
        user.setUsername(generateRandomUsername());

        userMapper.insert(user);

        Integer userId = user.getUserId();
        return Result.success("注册成功");
    }

    //  登录
    @Override
    public Result login(LoginData loginData) {

        if (!StringUtils.hasText(loginData.getIdentifier()) ||
                !StringUtils.hasText(loginData.getPassword())) {
            return Result.error("邮箱/手机号和密码不能为空");
        }

        // 识别标识类型 检查是邮箱还是手机号
        IdentifierType type = identifyIdentifierType(loginData.getIdentifier());
        if (type == null) {
            return Result.error("无效的邮箱或手机号格式");
        }

        // 得到用户
        User loginuser = isIdentifierRegistered(loginData.getIdentifier(), type);

        if (loginuser==null) {
            return Result.error("用户不存在，请注册");
        }

        if(loginuser.getStatus()==0){
            return Result.error("该用户已被禁用");
        }

        if(loginuser.getPassword().equals(MD5.create().digestHex(loginData.getPassword()))){

            Map<String,Object> claims=new HashMap<>();
            claims.put("userId",loginuser.getUserId());
            claims.put("username",loginuser.getUsername());
            claims.put("role",loginuser.getRole());

            // 登录成功，生成 JWT 令牌
            String token = JwtUtil.genToken(claims);
            //把token存储到redis中
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(token,token, 1, TimeUnit.HOURS);
            return Result.success(token);
        }

        return Result.error("密码错误，请重新输入");

    }

    //根据得到的类型手机号还是邮箱查看是否已存在
    @Override
    public User isIdentifierRegistered(String identifier, IdentifierType type) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (type == IdentifierType.EMAIL) {
            wrapper.eq(User::getEmail, identifier);
        } else {
            wrapper.eq(User::getPhone, identifier);
        }
        return userMapper.selectOne(wrapper);
    }

    //检查使用邮箱还是手机号
    private IdentifierType identifyIdentifierType(String identifier) {
        // 邮箱正则
        String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
        // 手机号正则 (示例为中国大陆手机号)
        String phoneRegex = "^1[3-9]\\d{9}$";

        if (identifier.matches(emailRegex)) {
            return IdentifierType.EMAIL;
        } else if (identifier.matches(phoneRegex)) {
            return IdentifierType.PHONE;
        }
        return null;
    }

    // 生成随机用户名（格式：user_时间戳_计数器）
    private String generateRandomUsername() {
        long timestamp = Instant.now().toEpochMilli();
        int counter = COUNTER.getAndIncrement() % 1000; // 限制计数器范围，避免溢出
        return String.format("user_%d_%03d", timestamp, counter);
    }

    // 密码复杂度检查方法
    private boolean isValidPassword(String password) {
        // 示例：至少8位，包含大小写字母、数字和特殊字符
        String regex = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=!])(?=\\S+$).{8,}$";
        return password.matches(regex);
    }
}  